/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/cat.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../impl/container_impl.h"
#include "../macro/head.h"
#include "connection.h"
#include "response.h"
#include "request.h"
#include "webapp.h"
#include "chain.h"
#include "task.h"

namespace cat
{
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static task::POOL * pool_ptr = 0;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

    task::task()
    {
        init_data();
    }

    task::~task()
    {
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int task::get_addr( POOL *** pppPool, void *** pppGroup, LIST *** pppList, T *** pppObj, xos_odbc::i_fields *** pppFields )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppGroup )
        {
            *pppGroup = 0;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        if( pppObj )
        {
            *pppObj = 0;
        }
        if( pppFields )
        {
            *pppFields = 0;
        }
        return ret;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    task * task::init_task( connection * pConnect, bool bAddToList )
    {
        task::T * pTask = task::get_item_from_pool( true );
        pTask->init();
        pTask->m_pConnection = pConnect;
        if( bAddToList )
        {
            pConnect->m_task_list.push_front( pTask );
            pTask->m_task_iter = pConnect->m_task_list.begin();
        }
        pConnect->lock_server();
        return pTask;
    }

    int task::term_task( task *& pTask )
    {
        int ret = 0;
        if( pTask )
        {
            connection * pConnect = pTask->m_pConnection;
            if( pTask->m_task_iter != pConnect->m_task_list.end() )
            {
                pConnect->m_task_list.erase( pTask->m_task_iter );
                pTask->m_task_iter = pConnect->m_task_list.end();
            }
            xos_stl::release_interface( pTask );
            pConnect->un_lock_server();
        }
        return ret;
    }

    int task::swap_http_request( task * pTask )
    {
        int ret = 0;
        ret = m_pRequest->swap_http_request( pTask->m_pRequest );
        return ret;
    }

    int task::un_lock_server_for_request_data()
    {
        int ret = 0;

        int num = m_pRequest->m_pUnEnctyptList->size() + m_pRequest->m_pUnPackageList->size() + m_pRequest->m_pUnCompressList->size() + m_pRequest->m_pRecvList->size();
        if( ( 0 == num ) && m_bServerLocked )
        {
            m_pConnection->un_lock_server();
            m_bServerLocked = false;
        }

        return ret;
    }

    int task::lock_server_for_request_data()
    {
        int ret = 0;

        int num = m_pRequest->m_pUnEnctyptList->size() + m_pRequest->m_pUnPackageList->size() + m_pRequest->m_pUnCompressList->size() + m_pRequest->m_pRecvList->size();
        if( ( num > 0 ) && !m_bServerLocked )
        {
            m_pConnection->lock_server();
            m_bServerLocked = true;
        }

        return ret;
    }

    int task::quit_close_test()
    {
        int ret = 0;

        xos::i_buf * pBuf = ( xos::i_buf * )m_pResponse->m_pEnctyptList->back( 0 );

        if( ( 0 == ret ) && !pBuf )
        {
            ret = 1;
        }

        if( ( 0 == ret ) && m_bCloseAfterSend )
        {
            m_pConnection->m_pCloseAfterSend = pBuf;
            ret = 1;
        }

        if( ( 0 == ret ) && m_bQuitAfterSend )
        {
            m_pConnection->m_pQuitAfterSend = pBuf;
            ret = 1;
        }

        return ret;
    }

    int task::init()
    {
        int ret = 0;

        if( 0 == ret )
        {
            ret = mgr::xos()->common()->create( xos_common::OBJ_PROPERTY, ( void** )&m_pProperty );
        }

        if( 0 == ret )
        {
            m_pResponse = response::get_item_from_pool( true );
            ret = m_pResponse->init();
        }

        if( 0 == ret )
        {
            m_pRequest = request::get_item_from_pool( true );
            ret = m_pRequest->init();
        }

        if( 0 == ret )
        {
            m_pProperty->set( "response", m_pResponse->prop(), false );
            m_pProperty->set( "request", m_pRequest->prop(), false );
        }

        return ret;
    }

    int task::term()
    {
        int ret = 0;

        xos_stl::release_interface( m_pProperty );
        xos_stl::release_interface( m_pResponse );
        xos_stl::release_interface( m_pRequest );

        init_data();

        return ret;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    xos_common::i_variant * task::helper_vt( const char * lpszVariable )
    {
        int ret = 0;

        xos::i_crt * pCrt = container_impl::get()->xos()->crt();
        chain * pChain = ( chain * )m_pChain;
        step * pStep = pChain->m_pCurStep;
        xos_common::i_variant * pRet = 0;

        // if find application ? 
        if( ( 0 == ret ) && ( 0 == pCrt->strcmp( lpszVariable, "application" ) ) )
        {
            pRet = prop()->vt( lpszVariable );
            if( !pRet )
            {
                prop()->set( lpszVariable, m_pWebApp, false );
                pRet = prop()->vt( lpszVariable );
            }
            if( pRet )
            {
                ret = 1;
            }
        }

        // find in current action map
        if( ( 0 == ret ) && pStep && pStep->m_pPlugin && pStep->m_pPlugin->m_pPlugin )
        {
            icat::i_plugin * pPlugin = pStep->m_pPlugin->m_pPlugin;
            icat::i_action * pAction = ( icat::i_action * )pPlugin;
            pRet = pAction->prop()->vt( lpszVariable );
            if( pRet )
            {
                ret = 1;
            }
        }

        // find in call stack
        for( step::ITER iter = pChain->m_call_stack.begin(); ( 0 == ret ) && ( iter != pChain->m_call_stack.end() ); ++iter )
        {
            step * pS = *iter;
            plugin * pP = pS->m_pPlugin;
            if( !pP )
            {
                continue;
            }
            icat::i_plugin * pPlugin = pP->m_pPlugin;
            if( !pPlugin )
            {
                continue;
            }
            icat::i_action * pAction = ( icat::i_action * )pPlugin;
            pRet = pAction->prop()->vt( lpszVariable );
            if( pRet )
            {
                ret = 1;
            }
        }

        // find in request.param
        if( 0 == ret )
        {
            pRet = m_pRequest->m_pParamProp->vt( lpszVariable );
            if( pRet )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            xos_common::i_property * pBodyListProp = m_pRequest->m_pTagProp->prop( xos_http::MULTIPART_BODY_LIST );
            xos_common::i_property * pVbProp = 0;
            if( pBodyListProp )
            {
                pVbProp = pBodyListProp->prop( lpszVariable );
            }
            if( pVbProp )
            {
                pRet = pVbProp->vt( xos_http::MULTIPART_BODY_VALUE );
            }
            if( pRet )
            {
                ret = 1;
            }
        }

        // find in request.tag
        if( 0 == ret )
        {
            pRet = m_pRequest->m_pTagProp->vt( lpszVariable );
            if( pRet )
            {
                ret = 1;
            }
        }

        // find in application
        if( 0 == ret )
        {
            pRet = m_pWebApp->prop()->vt( lpszVariable );
            if( pRet )
            {
                ret = 1;
            }
        }

        // find in task
        if( 0 == ret )
        {
            pRet = prop()->vt( lpszVariable );
            if( pRet )
            {
                ret = 1;
            }
        }

        return pRet;
    }

    int task::init_data()
    {
        int ret = 0;

        m_bCloseAfterSend = false;
        m_bQuitAfterSend = false;
        m_bRecving = false;

        m_pWebApp = 0;
        m_pChain = 0;

        m_pConnection = 0;
        m_pResponse = 0;
        m_pRequest = 0;

        m_peer_ip = "";
        m_nPeerPort = 0;

        m_bServerLocked = false;
        m_pProperty = 0;

        return ret;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // icat::i_task
    // 

    int task::add_ret_data( const char * lpszData, int nLen )
    {
        int ret = 0;
        ret = container_impl::get()->add_ret_data( this, lpszData, nLen );
        return ret;
    }

    int task::add_ret_data( xos::i_buf *& pBuf )
    {
        int ret = 0;
        ret = container_impl::get()->add_ret_data( this, pBuf );
        return ret;
    }

    int task::add_ret_str( const char * lpszStr )
    {
        int ret = 0;
        ret = container_impl::get()->add_ret_str( this, lpszStr );
        return ret;
    }

    int task::set_chain( icat::i_chain * pChain )
    {
        int ret = 0;
        m_pChain = pChain;
        return ret;
    }

    icat::i_chain * task::get_chain()
    {
        return m_pChain;
    }

    icat::i_webapp * task::app()
    {
        return m_pWebApp;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    xos_common::i_variant * task::vt( const char * lpszVariable )
    {
        int ret = 0;

        xos_common::i_misc * pCmnMisc = mgr::xos()->common_misc();
        xos::i_crt * pCrt = mgr::xos()->crt();

        xos_common::i_property * pProperty = 0;
        xos_common::i_variant * pRet = 0;

        char buf[4096];
        const char * lpszBuf = buf;
        int nLen = 0;
        int nPos = 0;

        if( 0 == ret )
        {
            buf[0] = 0;
            pCrt->strcpy( buf, sizeof( buf ), lpszVariable );
            pCmnMisc->trim( buf, " " );
            nLen = pCrt->strlen( buf );
        }

        for( int i = 0; ( 0 == ret ) && ( i < nLen ); ++i )
        {
            if( buf[i] == '.' )
            {
                buf[i] = 0;
            }
        }

        while( ( 0 == ret ) && ( nPos < nLen ) )
        {
            xos_common::i_property * pCurProperty = pProperty;
            xos_common::i_property * pNextProperty = 0;
            xos::i_unknown * pUnk = 0;
            lpszBuf = buf + nPos;
            if( pCurProperty )
            {
                pRet = pCurProperty->vt( lpszBuf );
            }
            else
            {
                pRet = helper_vt( lpszBuf );
            }
            if( pRet && ( xos_common::i_variant::VT_OBJECT == pRet->get_type( 0 ) ) )
            {
                pUnk = pRet->obj();
            }
            if( pUnk )
            {
                pUnk->query_interface( xos_common::i_property_id, ( void** )&pNextProperty );
            }
            if( pNextProperty )
            {
                pProperty = pNextProperty;
            }
            int len = pCrt->strlen( lpszBuf ) + 1;
            nPos += len;
        }

        return pRet;
    }

    xos::i_list * task::list( const char * lpszVariable )
    {
        xos_common::i_variant * pVT = vt( lpszVariable );
        xos::i_unknown * pUnk = 0;
        xos::i_list * pRet = 0;

        if( pVT && ( xos_common::i_variant::VT_OBJECT == pVT->get_type( 0 ) ) )
        {
            pUnk = pVT->obj();
        }

        if( pUnk )
        {
            pUnk->query_interface( xos::i_list_id, ( void** )&pRet );
        }

        return pRet;
    }

    const char * task::str( const char * lpszVariable )
    {
        xos_common::i_variant * pVT = vt( lpszVariable );
        const char * pRet = "";

        if( pVT )
        {
            pRet = pVT->str();
        }

        return pRet;
    }

    double task::dbl( const char * lpszVariable )
    {
        xos_common::i_variant * pVT = vt( lpszVariable );
        double ret = 0.0;

        if( pVT )
        {
            ret = pVT->dbl();
        }

        return ret;
    }

    float task::flt( const char * lpszVariable )
    {
        xos_common::i_variant * pVT = vt( lpszVariable );
        float ret = 0.0f;

        if( pVT )
        {
            ret = pVT->flt();
        }

        return ret;
    }

    int task::it( const char * lpszVariable )
    {
        xos_common::i_variant * pVT = vt( lpszVariable );
        int ret = 0;

        if( pVT )
        {
            ret = pVT->it();
        }

        return ret;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    icat::i_response * task::get_response()
    {
        return m_pResponse;
    }

    icat::i_request * task::get_request()
    {
        return m_pRequest;
    }

    const char * task::base_path()
    {
        return m_pWebApp->m_webapp_path.c_str();
    }

    xos_common::i_property * task::prop()
    {
        return m_pProperty;
    }

} // cat
